using System;
using System.Collections.Generic;
using System.Text;

namespace WOWEquipOptimizer.Warrior
{
    class Fury : MeleeDD
    {
        public Fury()
        {
            AllowTwoHand = false;
            AllowDualWield = true; 
            m_Base = new List<Attribute>();
            m_Base.Add(new Attribute(AttributeName.Health, 4264));
            m_Base.Add(new Attribute(AttributeName.Stamina, 135));
            m_Base.Add(new Attribute(AttributeName.Strength, 162));
            m_Base.Add(new Attribute(AttributeName.Agility, 93));
            m_Base.Add(new Attribute(AttributeName.CritRating, 1.14f * CritRating));
            // talents
            m_Base.Add(new Attribute(AttributeName.CritRating, 5 * CritRating));
            m_Base.Add(new Attribute(AttributeName.HitRating, 3 * HitRating));
            foreach (Attribute attr in m_Base)
            {
                handleAttribute(attr);
            }
            Buff soe = new Buff("Strength of Earth", new List<Attribute>());
            soe.Attributes.Add(new Attribute(AttributeName.Strength, 88 * 1.15f));
            Buffs.Add(soe);
            Buff wf = new Buff("Windfury Totem", new List<Attribute>());
            wf.Attributes.Add(new Attribute(AttributeName.Special, 12345678));
            Buffs.Add(wf);
        }
        // WDPS1, WDPS2, WS1, WS2, Crit,Hit, AP, Haste,health
        public override void handleAttribute(Attribute attr)
        {
            switch (attr.Type)
            {
                case AttributeName.Agility:
                    m_Equip[AttributeName.CritRating] += (attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) / 33f) * CritRating;
                    break;
                case AttributeName.CritMeleeRating:
                case AttributeName.CritRating:
                    m_Equip[AttributeName.CritRating] += attr.Value;
                    break;
                case AttributeName.HitMeleeRating:
                case AttributeName.HitRating:
                    m_Equip[AttributeName.HitRating] += attr.Value;
                    break;
                case AttributeName.AttackPower:
                    m_Equip[AttributeName.AttackPower] += attr.Value * 1.1f;
                    break;
                case AttributeName.Strength:
                    m_Equip[AttributeName.AttackPower] += attr.Value * (HasBlessingOfKings ? 1.1f : 1.0f) * 2 * 1.1f;
                    break;
                case AttributeName.HasteDirect:
                    m_Equip[attr.Type] = (((1 + (m_Equip[attr.Type] / HasteRating) / 100f) * (1 + attr.Value / 100)) - 1) * HasteRating * 100;
                    break;
                default:
                    base.handleAttribute(attr);
                    break;
            }
        }
        public override float evaluateTF()
        {
            float wdps1 = (float)m_Equip[AttributeName.MHWDPS];
            float wdps2 = (float)m_Equip[AttributeName.OHWDPS];
            float ws1 = (float)m_Equip[AttributeName.MHWS];
            float ws2 = (float)m_Equip[AttributeName.OHWS];
            float crit = (float)m_Equip[AttributeName.CritRating] / CritRating;
            float hit = (float)m_Equip[AttributeName.HitRating] / HitRating;
            float baseap = (float)m_Equip[AttributeName.AttackPower];
            float haste = (float)m_Equip[AttributeName.HasteRating] / HasteRating;
            if (wdps1 > 0 && ws1 > 0 && wdps2 > 0 && ws2 > 0)
            {
                float glancingreduction = 25; // XX% reduced damage
                float glancingchance = 25; // chance to happen == XX%
                float glancing = glancingreduction * glancingchance / 100; // this value is used in the closed-form of the attacktable below
                float dodge = 5.6f; // 5.6% dodge chance of the boss
                float ap = baseap;
                float hitwhite = (float)Math.Min(100 - 5 - 19 - 3.0f - 0.6f + hit, 100); // 100% - 5% base - 19% dw - 3% bossmalus- 0.6% wskilldifference + hit, upto array maximum of 100
                float hityellow = (float)Math.Min(100 - 5 - 3.0f - 0.6f + hit, 100);// 100% - 5% base - 3% bossmalus - 0.6% wskilldifference + hit, upto array maximum of 100
                float avghit = (hityellow + hitwhite) / 200; // average hit value, already normalized to 0<=x<=1
                float noncrit = (1 - crit / 100); // the chance not to crit
                float flurryvalue = 0.25f;
                // weapon speed incl.flurry
                // 25% * flurry uptime + possible haste effects, calculating the effective speed
                float flurryprob = (float)Math.Min(1 - Math.Pow(noncrit, 3f + 1 - Math.Pow(1 - 0.2f, 3) + ((ws1 + ws2) / 4 / 6)), 1.0);
                float wsmh = (ws1 / (1 + haste / 100)) * (1 - flurryprob) + (ws1 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob;
                float wsoh = (ws2 / (1 + haste / 100)) * (1 - flurryprob) + (ws2 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob;
                float avgspeed = (wsmh + wsoh) / 2; // average again for some stuff
                float hastemh = ws1 / wsmh;
                float hasteoh = ws2 / wsoh;
                float avghaste = (hastemh + hasteoh) / 2;
                
                if (this.SpecialValues.Contains("22071316"))
                {
                    ap += Math.Min(10.0f / avgspeed * (crit / 100f) * 0.1f * 340f, 340f);
                }
                float nocritinthree = (float) Math.Pow(1 - crit/100, 3 / avgspeed);
                float bleedcrit = crit * (1 + nocritinthree * 0.15f); // deep wounds // only assume one tick for now
                float mhwhitedps = 1 / 100f * (hitwhite + bleedcrit - glancing - dodge) * (wdps1 + ap / 14f); // normal   mh white swing dps
                float ohwhitedps = 0.75f * 1 / 100f * (hitwhite + bleedcrit - glancing - dodge) * (wdps2 + ap / 14f); // normal ohindex swing dps
                float wfdps = 0;
                if (this.SpecialValues.Contains("12345678"))
                {
                    float wfap = ap + 445 * 1.3f;
                    wfdps = 1 / 100f * 1 / 100f * (hitwhite - dodge) * (hityellow + bleedcrit - dodge) * 0.2f * (wdps1 + wfap / 14); // wf stuff
                }
                float normaldps = hastemh * (mhwhitedps + wfdps) + hasteoh * ohwhitedps; // sum it up put haste as array mult 
                float rageps = ((ohwhitedps+wfdps) * 15f) / (4 * 274.7f) + (1 + crit / 100) * (1.5f+0.4f) * 1/wsoh;
                float bloodthirstdmg = Math.Min(rageps * 6 / 30, 1) * (hityellow + bleedcrit * 1.2f - dodge) * 1 / 100f * (ap * 0.45f);
                float mhweapondmg = (wdps1 + ap / 14f) * ws1;                
                float hscount = (float) Math.Min(((rageps * 6) - 30) / 12, (6 - 1.5f) / wsmh);
                //float hsdmg=(hityellow + crit * 1.2f - dodge) * 1 / 100f * (mhweapondmg + 208);
                //float hsdmg = (208 / 100f + mhwhitedps / (hitwhite + bleedcrit - glancing - dodge)) * (hityellow + bleedcrit * 1.2f - dodge); // crude approximation
                float hsdmg = -((mhwhitedps * ws1 * 100) / (hitwhite + bleedcrit - glancing - dodge)) + (wdps1 + ap / 14f + 228 / ws1) * ws1 * (hityellow + bleedcrit * 1.2f - dodge) * 1 / 100f;
                float rotdmg = bloodthirstdmg + hscount * hsdmg;
                float rottime = 6f;
                float finaldps = normaldps + rotdmg/rottime;
                return CondFactor * Character.Armor * finaldps;
            }
            else return -1;
        }
        // 
        public override List<Item> filterEquip(List<Item> input)
        {
            input = base.filterEquip(input);
            List<Item> retval = new List<Item>();
            foreach (Item item in input)
            {
                if ((item.AllowableClasses & CharacterClass.Warrior) == 0) continue;
                if (item.GetType() == typeof(Weapon))
                {
                    Weapon weapon = (Weapon)item;
                    if (weapon.TwoHand) continue;
                }
                else if (item.GetType() == typeof(Armor))
                {
                    Armor armor = (Armor)item;
                    if ((armor.Type & ArmorProficiency.Plate) == 0) continue;
                    if (armor.Slot == ArmorSlot.OffHand) continue;
                }
                if (SetBlacklist.Contains(item.Set.Name)) continue;
                if (ItemBlacklist.Contains(item.Name)) continue;
                retval.Add(item);
            }
            return handleWhiteList(retval);
        }
        public override bool evaluateBuild(int[] build)
        {
            if (build[1] == 44 && build[0] == 17)
            {
                return true;
            }
            else return false;
        }
    }
}
